import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Scanner;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.im4java.core.IM4JavaException;
import org.im4java.process.ProcessStarter;

import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.TreeMultimap;

public class Window {

	private FormData formData;
	private FormLayout layout;
	private Display display;
	private Shell shell;
	private Text directoryText;
	private Button browseButton;
	private Button mapButton;
	private Composite composite;
	private Button md5Button;
	private Multimap<String, String> md5Map;
	private String MD5_PATH = "C:\\md5.txt";
	private SashForm sashFormPic;
	private Control buttonComposite;
	private Button bLeft;
	private Button bRight;
	
	public Window() {
		initImageMagik();

		display = new Display();
		shell = new Shell(display);
		shell.setSize(762, 539);
		shell.setSize(800, 600);
		shell.setText("Comparer");

		// layout
		layout = new FormLayout();
		shell.setLayout(layout);

		// element placement

		mapButton = new Button(shell, SWT.PUSH);
		mapButton.setText("MAP");
		formData = new FormData();
		formData.top = new FormAttachment(0, 0);
		formData.right = new FormAttachment(100, 0);
		mapButton.setLayoutData(formData);

		md5Button = new Button(shell, SWT.PUSH);
		md5Button.setText("MD5");
		formData = new FormData();
		formData.top = new FormAttachment(0, 0);
		formData.right = new FormAttachment(mapButton, 0);
		md5Button.setLayoutData(formData);

		browseButton = new Button(shell, SWT.PUSH);
		browseButton.setText("Browse");
		formData = new FormData();
		formData.top = new FormAttachment(0, 0);
		formData.right = new FormAttachment(md5Button, 0);
		browseButton.setLayoutData(formData);

		directoryText = new Text(shell, SWT.SINGLE | SWT.BORDER);
		formData = new FormData();
		formData.bottom = new FormAttachment(mapButton, 0, SWT.BOTTOM);
		formData.top = new FormAttachment(0, 0);
		formData.left = new FormAttachment(0, 0);
		formData.right = new FormAttachment(browseButton, 0);
		directoryText.setLayoutData(formData);

		composite = new Composite(shell, SWT.NONE);
		formData = new FormData();
		formData.top = new FormAttachment(directoryText, 0);
		formData.bottom = new FormAttachment(100, 0);
		formData.left = new FormAttachment(0, 0);
		formData.right = new FormAttachment(100, 0);
		composite.setLayoutData(formData);
		composite.setLayout(new FillLayout());

		sashFormPic = new SashForm(composite, SWT.HORIZONTAL);
		
		bLeft = new Button(sashFormPic, SWT.PUSH);
		bLeft.setText("Left");
		buttonComposite = new Composite(sashFormPic, SWT.BORDER);
		buttonComposite.setLayoutData(new RowLayout());
	    bRight = new Button(sashFormPic, SWT.PUSH);
	    bRight.setText("Right");
	    
	    sashFormPic.setWeights(new int[] { 5,1,5 });

	    
		// TODO : remove at the end
		directoryText.setText("C:\\Users\\Public\\Pictures\\Sample Pictures");

		// actions
		browseButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				DirectoryDialog dialog = new DirectoryDialog(shell);
				String path = dialog.open();
				if (path != null) {
					directoryText.setText(path);
				}
			}
		});
		mapButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				mapMD5(MD5_PATH);
			}
		});
		md5Button.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				if ("".equals(directoryText.getText())) {
					MessageDialog.openError(shell, "Error",
							"No directory selected");
					return;
				} else {
					try {
						getAllMD5(directoryText.getText());
					} catch (IOException | InterruptedException
							| IM4JavaException | NoSuchAlgorithmException e1) {
						e1.printStackTrace();
					}
				}
			}
		});

		display.addFilter(SWT.KeyUp, new Listener() {
			@Override
			public void handleEvent(Event e) {
				if ((e.stateMask & SWT.CTRL) == SWT.CTRL) {
					System.out.println("Ctrl pressed");
					Collection<String> list = getNextDuplication();	
					String[] array = list.toArray(new String[list.size()]);
					
					System.out.println(array[0] + " <-> " + array[1]);
					Image imageLeft = new Image(display, array[0]);
					Image imageRight = new Image(display, array[1]);
					bLeft.setImage(imageLeft);
					bRight.setImage(imageRight);
				} else if (e.keyCode == SWT.ESC) {
					System.out.println("Esc pressed");
				} else if (e.keyCode == SWT.SPACE) {
					System.out.println("Space pressed");
				}
			}
		});

		directoryText.setFocus();
		// end
		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
		display.dispose();
	}

	private void initImageMagik() {
		String myPath = "C:\\Program Files\\ImageMagick-6.8.9-Q16;C:\\Windows\\exifteel.exe;";
		ProcessStarter.setGlobalSearchPath(myPath);
	}

	private void mapMD5(String str) {
		System.out.println("---MAP MD5---");
		Path path = Paths.get(str);
		md5Map = TreeMultimap.create();

		try (Scanner scanner = new Scanner(path)) {
			while (scanner.hasNextLine()) {
				String[] tab = scanner.nextLine().split("::::");
				md5Map.put(tab[0], tab[1]);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		// Iterating over entire Mutlimap
		for (String key : md5Map.keySet()) {
			System.out.println(key + " --> " + md5Map.get(key).toString());
		}
	}

	private Collection<String> getNextDuplication() {
		System.out.println("---NEXT DUPLICATION IS---");
		if (md5Map != null) {		
			Collection<String> keys = md5Map.keys();
			if (!keys.isEmpty()) {
				Iterator<String> it = keys.iterator();
				while (it.hasNext()) {
					String key = it.next();
					Collection<String> values = md5Map.get(key);
					if (values.size() > 1) {
						return values;
					} else {
						continue;
					}
				}
			}
		}
		return null;
	}

	protected void getAllMD5(String directoryPath) throws IOException,
			InterruptedException, IM4JavaException, NoSuchAlgorithmException {
		System.out.println("---GET ALL MD5---");
		PrintWriter writer = new PrintWriter(MD5_PATH, "UTF-8");
		File folder = new File(directoryPath);
		File[] listOfFiles = folder.listFiles();
	    int i = 0;
		for (File file : listOfFiles) {
			String md5 = getMD5(file);
			System.out.println(++i +"/"+listOfFiles.length + "\t" + md5 + "::::" + file.getAbsolutePath());
			writer.println(md5 + "::::" + file.getAbsolutePath());
		}
		writer.close();

	}

	/**
	 * Compare two files with their MD5 hashes.
	 * 
	 * @param file1
	 * @param file2
	 * @return true if same, false if different.
	 * @throws NoSuchAlgorithmException
	 * @throws IOException
	 */
	private boolean compareMD5Files(File file1, File file2)
			throws NoSuchAlgorithmException, IOException {
		String md5_1 = getMD5(file1);
		String md5_2 = getMD5(file2);

		System.out.println(md5_1);
		System.out.println(md5_2);
		if (md5_1.equals(md5_2)) {
			System.out.println("same !\r\n");
			return true;
		} else {
			System.out.println("");
			return false;
		}
	}

	/**
	 * Get the MD5 hash of a file.
	 * 
	 * @param file
	 * @return
	 * @throws NoSuchAlgorithmException
	 * @throws IOException
	 */
	private String getMD5(File file) throws NoSuchAlgorithmException,
			IOException {
		MessageDigest md = MessageDigest.getInstance("MD5");
		FileInputStream fis = new FileInputStream(file);
		byte[] dataBytes = new byte[1024];
		int nread = 0;
		while ((nread = fis.read(dataBytes)) != -1) {
			md.update(dataBytes, 0, nread);
		}
		;
		byte[] mdbytes = md.digest();

		// convert the byte to hex format
		StringBuffer sb = new StringBuffer("");
		for (int i = 0; i < mdbytes.length; i++) {
			sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16)
					.substring(1));
		}

		return sb.toString();
	}
}